import base64
import json
import random
import socket
import threading
import time
import rsa
import sys
import os
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '../../')))
import sys
import os
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '../../')))
from backend.DID.BlockChain import query_data
from backend.DID.DataBase import search_data, search_did, private_key_changes
from backend.DID.Identity_Management import hashFunction
from backend.DID.Key_Management import k_insert_temporary_private_key, b_insert_temporary_private_key, \
    store_temporary_PublicKey

import sys
import os
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '../../')))
#跨机
"""获取本机IP"""
def get_ip_address():
    # 获取主机名称
    hostname = socket.gethostname()
    # 根据主机名称获取与之关联的IP地址
    ip_address = socket.gethostbyname(hostname)
    return ip_address

"""两位时候"""
# def get_network_segment(ip_address):
#     # 通过分割字符串来提取IP地址的前两部分
#     segments = ip_address.split('.')
#     if len(segments) >= 2:
#         return segments[0], segments[1]
#     else:
#         raise ValueError("Invalid IP address format")
#
# def broadcast_find_host(data, stop_event):  # 这个data包括设备信息和用户did
#     udp = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
#     udp.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
#
#     ip_address = get_ip_address()
#     part1, part2 = get_network_segment(ip_address)
#
#     broadcast_interval = 5 + random.random()*5
#     check_interval = 0.5
#
#     while not stop_event.is_set():
#         try:
#             print("[跨机] 发送广播查找本机...")
#             msg = f"FIND_HOST:{json.dumps(data)}".encode()
#             #print(f"msg:{msg}")
#             udp.sendto(msg, (f'{part1}.{part2}.255.255', 8800))
#         except Exception as e:
#             print(f"[跨机] 广播发送错误: {e}")
#         elapsed = 0
#         while elapsed < broadcast_interval and not stop_event.is_set():
#             time.sleep(check_interval)
#             elapsed += check_interval
#     udp.close()
#     print("[跨机] 广播线程已停止")

"""三位时候"""
#
# def broadcast_find_host(data, stop_event):  # 这个data包括设备信息和用户did
#     udp = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
#     udp.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
#
#     ip_address = get_ip_address()
#     part1, part2 = get_network_segment(ip_address)
#
#     broadcast_interval = 5 + random.random()*5
#     check_interval = 0.5
#
#     while not stop_event.is_set():
#         try:
#             print("[跨机] 发送广播查找本机...")
#             msg = f"FIND_HOST:{json.dumps(data)}".encode()
#             #print(f"msg:{msg}")
#             udp.sendto(msg, (f'{part1}.{part2}.255.255', 8800))
#         except Exception as e:
#             print(f"[跨机] 广播发送错误: {e}")
#         elapsed = 0
#         while elapsed < broadcast_interval and not stop_event.is_set():
#             time.sleep(check_interval)
#             elapsed += check_interval
#     udp.close()
#     print("[跨机] 广播线程已停止")

"""三位时候"""
def get_network_segment(ip_address):
    # 通过分割字符串来提取IP地址的前两部分
    segments = ip_address.split('.')
    if len(segments) >= 3:
        return segments[0], segments[1], segments[2]
    if len(segments) >= 3:
        return segments[0], segments[1], segments[2]
    else:
        raise ValueError("Invalid IP address format")

# 跨机

def broadcast_find_host(data, stop_event):  # 这个data包括设备信息和用户did
    udp = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    udp.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
    ip_address = get_ip_address()
    part1, part2 ,part3= get_network_segment(ip_address)

    broadcast_interval = 1 + random.random()*5
    # 检查间隔时间：用于控制等待广播间隔期间，检查停止信号的频率
    check_interval = 0.3
    broadcast_interval = 1 + random.random()*5
    # 检查间隔时间：用于控制等待广播间隔期间，检查停止信号的频率
    check_interval = 0.3

    while not stop_event.is_set():
        try:
            print("[跨机] 发送广播查找本机...")
            msg = f"FIND_HOST:{json.dumps(data)}".encode()
            #print(f"msg:{msg}")
            udp.sendto(msg, (f'{part1}.{part2}.{part3}.255', 3334))
            udp.sendto(msg, (f'{part1}.{part2}.{part3}.255', 3334))
        except Exception as e:
            print(f"[跨机] 广播发送错误: {e}")
        #已经等待时间
        #已经等待时间
        elapsed = 0
        while elapsed < broadcast_interval and not stop_event.is_set():
            time.sleep(check_interval)
            elapsed += check_interval
    udp.close()
    print("[跨机] 广播线程已停止")



#跨机

"""本机端口8810 -- 3334"""
def listen_for_host_response():
    udp = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    udp.bind(('', 3333))
    udp.settimeout(10)  # 缩短超时，便于重试
    retry_count = 0   #监听次数
    max_retries = 3   #最大监听次数
    udp.bind(('', 3333))
    udp.settimeout(10)  # 缩短超时，便于重试
    retry_count = 0   #监听次数
    max_retries = 3   #最大监听次数
    try:
        while retry_count < max_retries:
            try:
                msg, addr = udp.recvfrom(1024)
                #print(f"[跨机] 收到响应: {msg.decode()}，来自 {addr}")
                response_data = json.loads(msg.decode())
                benji_did = response_data.get("benji_user_did")
                if benji_did:
                    return {'benji_did': benji_did, 'host_addr': addr[0]}
                else:
                    print("响应缺少 benji_user_did 字段")
                    return None
            except json.JSONDecodeError:
                print("[跨机] JSON解析失败，重试...")
                retry_count += 1
            except socket.timeout:
                retry_count += 1
                print(f"[跨机] 接收超时，重试 {retry_count}/{max_retries}")
        return None
    finally:
        udp.close()

#whole_information格式要注意
def benji_create_authorization_file(benji_did,whole_information):
    try:
        whole_information_str = json.dumps(whole_information,sort_keys=True)
        whole_information_bytes = whole_information_str.encode("utf-8")
        de_private_key = private_key_changes(benji_did)     #该函数用于传入did找到私钥，该私钥可直接用于签名等作用
        signature = rsa.sign(whole_information_bytes, de_private_key, "SHA-256")  #是hash的方法SHA-256
        return signature,whole_information
    except Exception as e:
        print(f"DID部分创建授权文件出错，错误为{e}")
        return None

def kuaji_verify_authorization_file(signature,data,benji_device_information):
    try:
        signature = base64.b64decode(signature)  #发送方要进行Base64编码便于传输，但是rsa.verify()signature需要bytes格式，所有要先进行 base64解码再转为bytes格式
        if not isinstance(data, list):
            data = [data]   #先转成列表之后便于转成bytes格式
        #sort_keys=True加上这个是保证json化的顺序一致
        data_bytes = json.dumps(data,sort_keys = True).encode("utf-8")

        benji_device_information_tuple = tuple(benji_device_information)   #转成元组，hashFunction()必须是元组
        benji_hash1 = hashFunction(benji_device_information_tuple)
        #print(f"benji_hash1:{benji_hash1}")
        public_key = get_public_key(benji_hash1)  #get_public_key()这个函数直接吧公钥格式转了
        #print(f"public_key:{public_key}")
        if isinstance(data_bytes, str):
            data_bytes = data_bytes.encode('utf-8')
        rsa.verify(data_bytes,signature ,public_key)   #rsa的verify必须将data和signature转成bytes格式，公钥要转成rsa.PublicKey格式
        return 1
    except Exception as e:
        print(f"DID部分验证签名部分出错，错误为{e}")
        return 0
#数据库上
def get_hash2(hash1):
    db_path = 'user.db'
    table_name_hash2 = "user"
    condition_column = "hash1"
    data = "hash2"
    try:
        hash2 = search_data(db_path, table_name_hash2, condition_column, hash1, data)
        return hash2
    except Exception as e:
        print(f"DID部分查找hash2部分出错，错误为{e}")
def get_private_key(hash1):
    db_path = 'user.db'
    table_name_private_key = 'user'
    condition_column = "hash1"
    data = "private_key"
    try:
        private_key = search_data(db_path,table_name_private_key,condition_column,hash1,data)
        return private_key
    except Exception as e:
        print(f"DID部分查找私钥出错，错误为{e}")
#区块链上
def get_public_key(hash1_value):  #这函数已经将公钥转成可以直接进行rsa.verify()的公钥格式
    table_name_public_key = "blockchain"
    need_query_data_name = "publickey"
    index = {
        'hash1':f'{hash1_value}'
    }
    try:
        public_key_pem = query_data(table_name_public_key,index,need_query_data_name)
        public_key = rsa.PublicKey.load_pkcs1(public_key_pem.encode("UTF-8"))
        return public_key  #这里的公钥格式一个是pem
    except Exception as e:
        print(f"DID部分 查找公钥出错，错误为{e}")
def Certify(device_id,cpu_id,Disc_id,username,password,user_did):
    try:
        from backend.DID.DID_interface import DID_connect, DID_listen, DID_recv, DID_close
        from backend.DID.DataBase import insert_data
        device_data = (
            device_id,
            cpu_id,
            Disc_id
        )
        # 本机认证
        #print(f"user_did:{user_did}")
        kuaji_user_did = search_did()
        #print(f"kuaji_user_did:{kuaji_user_did}")
        if kuaji_user_did == user_did:
            #print("进入本机认证流程：")
            hash1 = hashFunction(device_data)
            whole_data = (
                device_data,
                username,
                password
            )
            user_hash_number1 = hashFunction(whole_data)
            user_hash_number2 = get_hash2(hash1)
            if user_hash_number1 == user_hash_number2:
                return f"本机认证成功"
            else:
                return f"本机认证失败"
        elif kuaji_user_did != user_did:
            # 跨机认证
            #print("[跨机] 进入跨机流程：")
            data = {
                'user_did': user_did,
                'kuaji_user_did': kuaji_user_did,
                'kuaji_device_information': device_data
            }
            stop_event = threading.Event()   #结束信号
            # 查找到本机
            kuaji_port = 3333
            kuaji_port = 3333
            try:
                broadcast_thread = threading.Thread(
                    target=broadcast_find_host,
                    args=(data, stop_event)
                )
                broadcast_thread.start()
                response = listen_for_host_response()
                # 检查 response 是否为 None
                if response is None:
                    print("未收到本机响应：您输入的DID有误或网络存在问题！")
                    return False
                benji_did = response['benji_did']
                benji_ip = response['host_addr']
                #print(benji_did)
                #print(benji_ip)
                # 停止广播线程
                stop_event.set()
                broadcast_thread.join()
                print(f"[跨机] 获取到本机信息: DID={benji_did}, IP={benji_ip}")
                #print(f"kuaji_user_did:{kuaji_user_did}")
                #print(f"kuaji_port:{kuaji_port}")
                # 跨机发送设备信息，请求授权
                if user_did == benji_did:
                    if not DID_listen(kuaji_user_did, kuaji_port):
                        print("监听失败")
                        # 接收授权数据
                    authorization_json_str = DID_recv()
                    print(f"[跨机] 收到本机数据：{authorization_json_str}")
                    if authorization_json_str:
                        authorization_data = json.loads(authorization_json_str)  # 添加这行解析JSON
                        if isinstance(authorization_data, dict):  # 现在检查解析后的数据
                            signature = authorization_data["signature"]
                            whole_device_data = authorization_data["data"]
                            temporary_Private_key_pem = authorization_data["temporary_PrivateKey"]  # pem格式
                            print(f"temporary_Private_key_pem:{temporary_Private_key_pem}")
                            # signature_bytes = signature.encode("UTF-8")
                            # temporary_Private_key = rsa.PrivateKey.load_pkcs1(temporary_Private_key_pem.encode("UTF-8"))
                            # print(f"temporary_Private_key:{temporary_Private_key}")
                            k_insert_temporary_private_key(benji_did, temporary_Private_key_pem)
                            print(f"signature:{signature}")   #字符串格式
                            # print(f"signature_bytes:{signature_bytes}")
                            print(f"whole_device_data:{whole_device_data}")  #列表
                            # print(f"temporary_Private_key:{temporary_Private_key}") #pem格式
                            benji_device_information = whole_device_data[len([device_id, cpu_id, Disc_id]):]
                            print(f"benji_device_information:{benji_device_information}")
                            index = kuaji_verify_authorization_file(signature, whole_device_data,
                                                                    benji_device_information)
                            # print(index)
                            if index == 1:
                                return "跨机认证成功"
                            else:
                                return "跨机认证失败"
                    else:
                        print("您输入的DID错误！")
            finally:
                stop_event.set()
                broadcast_thread.join(timeout=5)
                DID_close()
                print("连接关闭！")
    except Exception as e:
        print(f"DID部分认证方面出错，错误为{e}")

def benji(info):
    try:
        from backend.DID.DID_interface import DID_connect, DID_send
        from backend.DID.Key_Management import generate_pair_key
        kuaji_port = 3333
        kuaji_port = 3333
        result = host_udp_listener1()
        print(f"result:{result}")
        c = info.get("cpu_id")
        d = info.get("disk_id")
        p = info.get("product_id")
        if not result:
            print("监听过程被意外终止")
            return False
        benji_user_did = result['benji_user_did']
        kuaji_user_did = result['kuaji_user_did']
        kuaji_device_information = result['kuaji_device_information']
        print(benji_user_did)
        print(kuaji_user_did)
        print(kuaji_device_information)
        benji_device_information = [p, c, d]
        whole_information = kuaji_device_information + benji_device_information
        signature, data = benji_create_authorization_file(benji_user_did,whole_information)
        temporary_PublicKey_pem,temporary_PrivateKey_pem = generate_pair_key()
        b_insert_temporary_private_key(kuaji_user_did,temporary_PrivateKey_pem)
        store_temporary_PublicKey(benji_user_did,kuaji_user_did,temporary_PublicKey_pem)
        signature_b64 = base64.b64encode(signature).decode('utf-8')
        whole_data = {
            "signature":signature_b64,
            "data":data,
            "temporary_PrivateKey":temporary_PrivateKey_pem,
        }
        whole_data_json = json.dumps(whole_data)
        print(f"whole_data_json :{whole_data_json}")
        kuaji_ip = result.get('kuaji_ip')
        # print(f"kuaji_ip:{kuaji_ip}")

        if DID_connect(kuaji_user_did, kuaji_port, benji_user_did, kuaji_ip):
            print("连接跨机成功，准备发送数据...")
            if DID_send(whole_data_json):  # 直接发送 JSON 字符串
                print("数据发送成功！")
                time.sleep(5)  # 等待跨机处理，不立即关闭连接
            else:
                print("数据发送失败！")
                return False
    except Exception as e:
        print(f"DID部分跨机认证的本机方面出错，错误为{e}")
        return False
    return True

def host_udp_listener1():
    udp = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    udp.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    # 绑定所有网络接口的 8800 端口（正确）
    udp.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    # 绑定所有网络接口的 8800 端口（正确）
    try:
        udp.bind(('', 3334))
        udp.bind(('', 3334))
    except OSError as e:
        print(f"[本机] 绑定3334端口失败：{e}（可能被占用）")
        print(f"[本机] 绑定3334端口失败：{e}（可能被占用）")
        udp.close()
        return None
    udp.settimeout(30)
    print("[本机] 正在监听跨机广播请求...")
    try:
        while True:
            try:
                msg, addr = udp.recvfrom(1024)
                print(f"[本机] 收到来自 {addr}跨机请求")
                # 检查消息前缀格式（增强健壮性）
                if not msg.startswith(b"FIND_HOST:"):
                    print("[本机] 消息格式错误,不是FIND_HOST前缀")
                    print("[本机] 消息格式错误,不是FIND_HOST前缀")
                    continue
                # 拆分JSON部分，处理可能的IndexError
                try:
                    json_str = msg.decode().split(":", 1)[1]
                except IndexError:
                    print("[本机] 消息格式错误,缺少JSON部分")
                    print("[本机] 消息格式错误,缺少JSON部分")
                    continue
                # 解析JSON，已处理JSONDecodeError
                try:
                    data = json.loads(json_str)
                except json.JSONDecodeError:
                    print("[本机] JSON解析失败,等待下一条消息...")
                    print("[本机] JSON解析失败,等待下一条消息...")
                    continue

                # 验证必要字段是否存在
                required_fields = ["user_did", "kuaji_user_did", "kuaji_device_information"]
                if not all(field in data for field in required_fields):
                    print(f"[本机] 跨机请求缺少必要字段：{required_fields}")
                    continue
                user_did = data["user_did"]
                kuaji_user_did = data["kuaji_user_did"]
                kuaji_device_information = data["kuaji_device_information"]
                # 验证本机DID有效性
                benji_user_did = search_did()
                if not benji_user_did or not isinstance(benji_user_did, str):
                    print(f"[本机] 获取本机DID失败（值为：{benji_user_did}）")
                    continue  # 不回复，继续监听
                # 比较DID是否匹配
                if user_did == benji_user_did:
                    #print(f"[本机] 跨机DID与本机一致（{user_did}）")
                    # 构造响应数据
                    response_data = {
                        "benji_user_did": benji_user_did
                    }
                    response_msg = json.dumps(response_data).encode()
                    cross_ip = addr[0]  # 跨机的IP
                    cross_port = 3333  # 跨机监听响应的端口
                    cross_port = 3333  # 跨机监听响应的端口
                    # 发送响应
                    try:
                        udp.sendto(response_msg, (cross_ip, cross_port))
                        print(f"[本机] 已回应跨机 {cross_ip}")
                        # 若只需处理一个请求，返回结果；若需持续监听，注释此行
                        return {
                            'benji_user_did': benji_user_did,
                            'kuaji_user_did': kuaji_user_did,
                            'kuaji_device_information': kuaji_device_information,
                            'kuaji_ip': cross_ip
                        }
                    except Exception as e:
                        print(f"[本机] 发送响应失败：{e}")
                else:
                    print(f"[本机] 跨机DID（{user_did}）与本机DID（{benji_user_did}）不匹配，不回复")
            except Exception as e:
                print(f"[本机] 处理消息时出错: {e}")
                # 发生非致命错误时继续监听（而非break）
                continue
    finally:
        udp.close()
        print("[本机] UDP监听已关闭")
    return None



















